home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * Copyright (c) 2009 Michel Gutierrez. All Rights Reserved.
- ******************************************************************************/
-
- /**
- * Constants.
- */
-
- const NS_DOMHOOK_CID = Components.ID("{7e757f8b-0a62-4e65-9339-4b4fd1cb9bcc}");
- const NS_DOMHOOK_PROG_ID = "@downloadhelper.net/dom-hook;1";
- const DHNS = "http://downloadhelper.net/1.0#";
-
- var Util=null;
-
- /**
- * Object constructor
- */
- function Hook() {
- try {
- //dump("[Hook] constructor\n");
- var prefService=Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefService);
- this.pref=prefService.getBranch("dwhelper.");
- this.core=Components.classes["@downloadhelper.net/core;1"].
- getService(Components.interfaces.dhICore);
- } catch(e) {
- dump("[Hook] !!! constructor: "+e+"\n");
- }
- }
-
- Hook.prototype = {}
-
- Hook.prototype.hook=function(document) {
- //dump("[Hook] hook("+document.URL+")\n");
- try {
- var ytInPage=this.pref.getBoolPref("yt-inpage");
- if(ytInPage) {
- this.ytHook(document);
- }
- } catch(e) {
- dump("!!! [Hook] hook("+document.URL+"): "+e+"\n");
- }
- }
-
- Hook.prototype.ytHook=function(document) {
- if(/^http:\/\/(?:[a-z]+\.)?youtube\.com\//.test(document.URL)) {
- //dump("[Hook] hook(): YouTube page\n");
- var titleH1=Util.xpGetSingleNode(document.documentElement,".//div[@id='watch-vid-title']/h1");
- if(!titleH1) {
- dump("!!! [Hook] hook(): title not found\n");
- return;
- }
-
- var xulNS="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-
- var img=document.createElementNS(xulNS,"xul:toolbarbutton");
- img.setAttribute("image","http://www.downloadhelper.net/favicon.ico");
- img.setAttribute("type","menu-button");
- img.style.margin="0px 12px 0px 0px";
- img.style.position="relative";
- img.style.top="-3px";
-
- var menupopup=document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul","xul:menupopup");
- menupopup.setAttribute("position","end_before");
- img.appendChild(menupopup);
-
- var entries=this.core.getEntriesForDocument(document);
- if(entries.length==0) {
- dump("!!! [Hook] ytHook(): no entry for: "+document.URL+"\n");
- return;
- }
- var ytEntry=this.core.cloneEntry(entries.queryElementAt(0,Components.interfaces.nsIProperties));
-
- function Listener(core,entry,processor) {
- this.core=core;
- this.entry=entry;
- this.processor=processor;
- }
- Listener.prototype={
- handleEvent: function(event) {
- try {
- if(this.processor.canHandle(this.entry)) {
- this.updateEntry();
- this.core.processEntry(this.processor,this.entry);
- } else {
- var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
- .getService(Components.interfaces.nsIWindowMediator);
- var window = wm.getMostRecentWindow("navigator:browser");
- window.alert(Util.getFText("yt-inpage.unavailable-processor",[this.processor.title],1));
- }
- } catch(e) {
- dump("!!! [Hook] ytHook.handleEvent(): "+e+"\n");
- }
- event.stopPropagation();
- },
- updateEntry: function() {
- var pageUrl=Util.getPropsString(this.entry,"page-url");
- var mediaUrl=null;
- var fileExtension=null;
- var i=this.core.getEntries().enumerate();
- while(i.hasMoreElements()) {
- var entry=i.getNext().QueryInterface(Components.interfaces.nsIProperties);
- if(entry.has("media-url") && entry.has("page-url") && entry.has("capture-method") &&
- Util.getPropsString(entry,"page-url")==pageUrl &&
- Util.getPropsString(entry,"capture-method")=="network") {
- mediaUrl=Util.getPropsString(entry,"media-url");
- fileExtension=Util.getPropsString(entry,"file-extension");
- }
- }
- if(mediaUrl) {
- this.entry=this.core.cloneEntry(this.entry);
- Util.setPropsString(this.entry,"media-url",mediaUrl);
- Util.setPropsString(this.entry,"file-name",Util.getPropsString(this.entry,"base-name")+"."+fileExtension);
- }
- }
- }
-
- var defProcName=this.pref.getCharPref("yt-inpage.default-processor");
- var defProcessor=null;
-
- var i=this.core.getProcessors().enumerate();
- while(i.hasMoreElements()) {
- var processor=i.getNext().QueryInterface(Components.interfaces.dhIProcessor);
- if(processor.name==defProcName)
- defProcessor=processor;
- if(processor.canHandle(ytEntry)) {
- var menuitem=document.createElementNS(xulNS,"xul:menuitem");
- menuitem.setAttribute("label",processor.title);
- menuitem.setAttribute("tooltiptext",processor.description);
- menuitem.QueryInterface(Components.interfaces.nsIDOMNSEventTarget).
- addEventListener("command",new Listener(this.core,ytEntry,processor),false,false);
- menupopup.appendChild(menuitem);
- }
- }
- if(defProcessor)
- img.QueryInterface(Components.interfaces.nsIDOMNSEventTarget).
- addEventListener("command",new Listener(this.core,ytEntry,defProcessor),false,false);
- titleH1.insertBefore(img,titleH1.firstChild);
- }
- }
-
- Hook.prototype.QueryInterface = function(iid) {
- //dump("[Hook] QueryInterface("+iid+")\n");
- if(
- iid.equals(Components.interfaces.dhIDOMHook) ||
- iid.equals(Components.interfaces.nsISupports)
- ) {
- return this;
- }
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
-
- var vHookModule = {
- firstTime: true,
-
- /*
- * RegisterSelf is called at registration time (component installation
- * or the only-until-release startup autoregistration) and is responsible
- * for notifying the component manager of all components implemented in
- * this module. The fileSpec, location and type parameters are mostly
- * opaque, and should be passed on to the registerComponent call
- * unmolested.
- */
- registerSelf: function (compMgr, fileSpec, location, type) {
-
- if (this.firstTime) {
- this.firstTime = false;
- throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
- }
- compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
- compMgr.registerFactoryLocation(NS_DOMHOOK_CID,
- "Hook",
- NS_DOMHOOK_PROG_ID,
- fileSpec,
- location,
- type);
- },
-
- unregisterSelf: function(compMgr, fileSpec, location) {
- compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
- compMgr.unregisterFactoryLocation(NS_DH_DOMHOOK_CID, fileSpec);
- },
-
- /*
- * The GetClassObject method is responsible for producing Factory and
- * SingletonFactory objects (the latter are specialized for services).
- */
- getClassObject: function (compMgr, cid, iid) {
- if (!cid.equals(NS_DOMHOOK_CID)) {
- throw Components.results.NS_ERROR_NO_INTERFACE;
- }
-
- if (!iid.equals(Components.interfaces.nsIFactory)) {
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- }
-
- return this.vHookFactory;
- },
-
- /* factory object */
- vHookFactory: {
- /*
- * Construct an instance of the interface specified by iid, possibly
- * aggregating it with the provided outer. (If you don't know what
- * aggregation is all about, you don't need to. It reduces even the
- * mightiest of XPCOM warriors to snivelling cowards.)
- */
- createInstance: function (outer, iid) {
- if (outer != null) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
- }
-
- if(Util==null)
- Util=Components.classes["@downloadhelper.net/util-service;1"]
- .getService(Components.interfaces.dhIUtilService);
-
- return new Hook().QueryInterface(iid);
- }
- },
-
- /*
- * The canUnload method signals that the component is about to be unloaded.
- * C++ components can return false to indicate that they don't wish to be
- * unloaded, but the return value from JS components' canUnload is ignored:
- * mark-and-sweep will keep everything around until it's no longer in use,
- * making unconditional ``unload'' safe.
- *
- * You still need to provide a (likely useless) canUnload method, though:
- * it's part of the nsIModule interface contract, and the JS loader _will_
- * call it.
- */
- canUnload: function(compMgr) {
- return true;
- }
- };
-
- function NSGetModule(compMgr, fileSpec) {
- return vHookModule;
- }
-
-